#pragma once
#include "../common/dispacher.hpp"
#include "requestor.hpp"
#include "rpc_caller.hpp"
#include "rpc_registry.hpp"
#include "rpc_topic.hpp"
namespace bitpr
{
    namespace client
    {
        class RegistryClient
        {

        public:
            using ptr = std::shared_ptr<RegistryClient>;
            // 基本参数用于注册
            RegistryClient(const std::string &ip, int port) : _requestor(std::make_shared<Requestor>()), _provider(std::make_shared<client::Provider>(_requestor)), _dispacher(std::make_shared<Dispacher>())
            {
                auto rsp_cb = std::bind(&client::Requestor::onResponse, _requestor.get(),
                                        std::placeholders::_1, std::placeholders::_2); // 设置回调函数
                _dispacher->registerHandler<BaseMessage>(MType::RSP_SERVICE, rsp_cb);  // 将这个dispacher与回调函数结合
                auto message_cb = std::bind(&Dispacher::onMessage, _dispacher.get(),
                                            std::placeholders::_1, std::placeholders::_2);
                _client = ClientFactory::create(ip, port);
                _client->setMessageCallback(message_cb);
                _client->connect();
            }
            // 向外提供的注册接口
            bool registryMethod(const std::string &method, const Address &host)
            {
                return _provider->registryMethod(_client->connection(), method, host);
            }

        private:
            client::Provider::ptr _provider;
            Requestor::ptr _requestor;
            Dispacher::ptr _dispacher;
            BaseClient::ptr _client;
        };
        class DiscoveryClient
        {

        public:
            using ptr = std::shared_ptr<DiscoveryClient>;
            DiscoveryClient(const std::string &ip, int port, const Discoverer::OfflineCallback &cb) : _requestor(std::make_shared<Requestor>()), _discoverer(std::make_shared<client::Discoverer>(_requestor, cb)), _dispacher(std::make_shared<Dispacher>())
            {
                auto rsp_cb = std::bind(&client::Requestor::onResponse, _requestor.get(),
                                        std::placeholders::_1, std::placeholders::_2); // 设置回调函数
                _dispacher->registerHandler<BaseMessage>(MType::RSP_SERVICE, rsp_cb);  // 将这个dispacher与回调函数结合
                auto req_cb = std::bind(&client::Discoverer::onServiceRequest, _discoverer.get(),
                                        std::placeholders::_1, std::placeholders::_2);
                _dispacher->registerHandler<ServiceRequest>(MType::REQ_SERVICE, req_cb);

                auto message_cb = std::bind(&Dispacher::onMessage, _dispacher.get(),
                                            std::placeholders::_1, std::placeholders::_2);
                _client = ClientFactory::create(ip, port);
                _client->setMessageCallback(message_cb);
                _client->connect();
            }
            bool serviceDiscovery(const std::string method, Address &host)
            {
                return _discoverer->serviceDiscovery(_client->connection(), method, host);
            }

        private:
            client::Discoverer::ptr _discoverer;
            Requestor::ptr _requestor;
            Dispacher::ptr _dispacher;
            BaseClient::ptr _client;
        };
        class RpcClient
        {

        public:
            using ptr = std::shared_ptr<RpcClient>;
            // 是否启用这个服务发现功能,也决定传入的地址是这个注册中心还是服务提供这个
            RpcClient(bool enableDiscovery, const std::string &ip, int port) : _enableDiscovery(enableDiscovery),
                                                                               _requestor(std::make_shared<Requestor>()),
                                                                               _dispacher(std::make_shared<Dispacher>()),
                                                                               _caller(std::make_shared<bitpr::client::RpcCaller>(_requestor))
            {
                // 针对rpc请求的回调函数
                auto rsp_cb = std::bind(&client::Requestor::onResponse, _requestor.get(),
                                        std::placeholders::_1, std::placeholders::_2);
                _dispacher->registerHandler<BaseMessage>(MType::RSP_RPC, rsp_cb);
                // 启动这个服务发现,就是客户端需要链接的地址,通过地址实例化这个discovery_client
                // 如果没有启动这个服务发现,地址信息就是服务提供者的地址,直接实例化这个rpc_client
                _dispacher->registerHandler<BaseMessage>(MType::RSP_RPC, rsp_cb);
                if (_enableDiscovery)
                {
                    auto offline_cb = std::bind(&RpcClient::delClient, this, std::placeholders::_1);
                    _discovery_client = std::make_shared<DiscoveryClient>(ip, port, offline_cb);
                }
                else
                {
                    auto message_cb = std::bind(&Dispacher::onMessage, _dispacher.get(),
                                                std::placeholders::_1, std::placeholders::_2);
                    _rpc_client = ClientFactory::create(ip, port);
                    _rpc_client->setMessageCallback(message_cb);
                    _rpc_client->connect();
                }
            }
            bool call(const std::string &method, const Json::Value &params, Json::Value &result)
            {
                // 1服务发现 2固定服务提供者
                BaseClient::ptr client = getClient(method);
                if (client.get() == nullptr)
                {
                    return false;
                }
                return _caller->call(client->connection(), method, params, result);
            }
            bool call(const std::string &method, const Json::Value &params, RpcCaller::JsonAsyncResponse &result)
            {
                BaseClient::ptr client = getClient(method);
                if (client.get() == nullptr)
                {
                    return false;
                }
                // 3. 通过客户端连接，发送rpc请求
                return _caller->call(client->connection(), method, params, result);
            }
            bool call(const std::string &method, const Json::Value &params, const RpcCaller::JsonResponseCallback &cb)
            {
                BaseClient::ptr client = getClient(method);
                if (client.get() == nullptr)
                {
                    return false;
                }
                // 3. 通过客户端连接，发送rpc请求
                return _caller->call(client->connection(), method, params, cb);
            }

        private:
            BaseClient::ptr newClient(const Address &host)
            {
                auto message_cb = std::bind(&Dispacher::onMessage, _dispacher.get(),
                                            std::placeholders::_1, std::placeholders::_2);
                auto client = ClientFactory::create(host.first, host.second);
                client->setMessageCallback(message_cb);
                client->connect();
                putClient(host, client); // 插入到数组里面
                return client;
            }
            BaseClient::ptr getClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _rpc_clients.find(host);
                if (it == _rpc_clients.end())
                {
                    return BaseClient::ptr();
                }
                return it->second;
            }
            BaseClient::ptr getClient(const std::string method)
            {
                BaseClient::ptr client;
                if (_enableDiscovery)
                {
                    // 1 通过服务发现获取这个提供者的地址信息
                    Address host;
                    bool ret = _discovery_client->serviceDiscovery(method, host); // 服务发现
                    if (ret == false)
                    {
                        ELOG("当前服务%s,没有找到服务提供者", method.c_str());
                        return BaseClient::ptr();
                    }
                    // 2查看这个服务提供者是否有实例化的客户端,有就直接用,没有就创建
                    client = getClient(host);
                    if (client.get() == nullptr)
                    {
                        client = newClient(host);
                    }
                }else{
                    client=_rpc_client;//连接池找
                }
                return client;
            }
            void putClient(const Address &host, BaseClient::ptr &client)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _rpc_clients.insert(std::make_pair(host, client));
            }
            void delClient(const Address &host)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                _rpc_clients.erase(host);
            }
            struct AddressHash
            {
                size_t operator()(const Address &host) const
                {
                    std::string addr = host.first + std::to_string(host.second);
                    return std::hash<std::string>{}(addr);
                }
            };
            bool _enableDiscovery;
            DiscoveryClient::ptr _discovery_client;
            RpcCaller::ptr _caller;
            Requestor::ptr _requestor;
            Dispacher::ptr _dispacher;
            BaseClient::ptr _client;
            std::mutex _mutex;
            BaseClient::ptr _rpc_client;                                            // 连接池的成员
            std::unordered_map<Address, BaseClient::ptr, AddressHash> _rpc_clients; // 用于服务连接池
        };
           class TopicClient {
            public:
                TopicClient(const std::string &ip, int port):
                    _requestor(std::make_shared<Requestor>()),
                    _dispacher(std::make_shared<Dispacher>()),
                    _topic_manager(std::make_shared<TopicManager>(_requestor)) {
                    
                    auto rsp_cb = std::bind(&Requestor::onResponse, _requestor.get(), 
                        std::placeholders::_1, std::placeholders::_2);
                    _dispacher->registerHandler<BaseMessage>(MType::RSP_TOPIC, rsp_cb);

                    auto msg_cb = std::bind(&TopicManager::onPublish, _topic_manager.get(),
                        std::placeholders::_1, std::placeholders::_2);
                    _dispacher->registerHandler<TopicRequest>(MType::REQ_TOPIC, msg_cb);
                    
                    auto message_cb = std::bind(&Dispacher::onMessage, _dispacher.get(), 
                        std::placeholders::_1, std::placeholders::_2);
                    _rpc_client = ClientFactory::create(ip, port);
                    _rpc_client->setMessageCallback(message_cb);
                    _rpc_client->connect();
                }
                bool create(const std::string &key) {
                    return _topic_manager->create(_rpc_client->connection(), key);
                }
                bool remove(const std::string &key) {
                    return _topic_manager->remove(_rpc_client->connection(), key);
                }
                bool subscribe(const std::string &key, const TopicManager::SubCallback &cb) {
                    return _topic_manager->subscribe(_rpc_client->connection(), key, cb);
                }
                bool cancel(const std::string &key) {
                    return _topic_manager->cancel(_rpc_client->connection(), key);
                }
                bool publish(const std::string &key, const std::string &msg) {
                    return _topic_manager->publish(_rpc_client->connection(), key, msg);
                }
                void shutdown() {
                    _rpc_client->shutdown();
                }
            private:
                Requestor::ptr _requestor;
                TopicManager::ptr _topic_manager;
                Dispacher::ptr _dispacher;
                BaseClient::ptr _rpc_client;//用于未启用服务发现
        };

    } // namespace client

} // namespace bitpr
